package main

import (
	"fmt"
	"sync"
)

// 第十一章 goroutine 和 channel

func demo11() {

	/*
		fmt.Println("*************** 开启协程 Run函数 ***************")
		go Run()

		i := 0
		for i < 10000 {
			i++
			if i%200 == 0 {
				fmt.Println(i)
			}
		}
	*/

	/*
		fmt.Println("***************** 强制等待协程完成后才能运行 主要函数参数需要*引用地址 ******************")
		var wg sync.WaitGroup
		wg.Add(1)
		go RunWg(&wg)
		wg.Wait()
		//go Run()
		for i := 0; i < 100; i++ {
			fmt.Println("11")
		}
	*/

	/*
		fmt.Println("***************** channel 缓冲区特点 是否有 缓冲区 是否满了 ******************")
		// 掌握点：缓冲区 执行顺序 取决于是否缓冲区是否满了
		// 有缓存区 会先存满才进行读取 放出来
		c1 := make(chan int, 2)
		// c1 := make(chan int) //如果没有缓存区 直接读取会报错 <-c1 需要靠自执行函数
		// 程序是 从上往下的 如果没有缓冲区 <-c1读取的时候 就会进行获取c1的值
		// c1 <- 写  读 <-c1
		//c1 <- 1 // 无缓冲区会报错 需要自执行函数 且 加协程 go 可通过打印断点进行查看程序执行
		go func() {
			//c1 <- 2
			for i := 0; i < 5; i++ {
				c1 <- i
			}
		}()
		// 有缓冲区就是 首次读取<- 会进行设置 之后会执行设置的语句 直到执行完毕后再继续打印
		// 无缓冲区的话 读取的时候才会进行 设置值 可以通过断点调式
		for i := 0; i < 5; i++ {
			fmt.Println(<-c1)
		}
	*/

	/*
		fmt.Println("************************ channel 可读可写 close 关闭 ************************")
		c1 := make(chan int, 5)
		var readc <-chan int = c1
		var writec chan<- int = c1
		//readc<- 写入就报错
		// <-writec 读取也报错
		writec <- 2
		writec <- 3
		// 关闭后 不让写入 但是可以读取 不再需要往里面存取数据时候
		//close(c1)
		//writec <- 3

		//fmt.Println(<-readc)
		//fmt.Println(<-readc)
		//fmt.Println(<-readc) 报错因为只写了 2次

		// 如果需要取出所有 c1存储的值 用range 但是必须关闭掉
		close(c1)
		for v := range readc {
			fmt.Println(v)
		}

	*/

	/*
		fmt.Println("************************ channel select ************************")
		c1 := make(chan int, 1)
		c2 := make(chan int, 1)
		c3 := make(chan int, 1)

		// 值
		c1 <- 1
		c2 <- 2
		c3 <- 3

		// 如果三个都是有值的 那么就随机读取
		select {
		case <-c1:
			fmt.Println("c1")
		case <-c2:
			fmt.Println("c2")
		case <-c3:
			fmt.Println("c3")
		default:
			fmt.Println("都不满足")
		}
	*/

	fmt.Println("********************* channel 实际应用 *********************")

	c := make(chan int)
	var readc <-chan int = c
	var writec chan<- int = c
	go SetChan(writec)

	GetChan(readc)
}

func SetChan(writec chan<- int) {
	for i := 0; i < 10; i++ {
		writec <- i
	}
}

func GetChan(readc <-chan int) {
	for i := 0; i < 10; i++ {
		fmt.Printf("我是在get函数，取出来 SetChan中返回的的值是：%d\n", <-readc)
	}
}

func RunWg(wg *sync.WaitGroup) {
	fmt.Println("协程开始运行")
	wg.Done()
}

func Run() {
	fmt.Println("**后面运行的**")
}
